package com.wesley.schedule.support.schedule;

import com.wesley.schedule.domain.entity.ScheduleJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.stereotype.Component;

/**
 * ScheduleExecutor
 *
 * @author WangPanYong
 * @since 2021/04/13 11:34
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ScheduleExecutor {

    private final Scheduler scheduler;
    private final ScheduleService scheduleService;

    /**
     * Cron触发器命名 前缀
     */
    public static final String CRON_TRIGGER_PREFIX = "TRIGGER_";

    /**
     * 执行调度任务
     * @author WangPanYong
     * @since 2021/04/13 14:25
     **/
    public void execute(ScheduleJob job) {
        String jobId = job.getJobId();
        try {
            Object[] arguments = {job};
            JobDetail jobDetail = buildJobDetail(scheduleService, ScheduleService.METHOD_PROXY, jobId, job.getJobType(), arguments);
            String triggerName = CRON_TRIGGER_PREFIX + job.getJobId();
            String triggerGroup = CRON_TRIGGER_PREFIX + job.getJobType();
            Trigger trigger = buildCronTrigger(jobDetail, job.getCronExpression(), triggerName, triggerGroup);
            scheduler.scheduleJob(jobDetail, trigger);
            log.info(" ====> 调度ScheduleJob开始! JobId = {}", jobId);
        } catch (Exception e) {
            log.error(" ====> 调度ScheduleJob失败! jobId = {}", jobId);
            log.error(e.getMessage(), e);
        }
    }


    /**
     *
     * @param object 代理对象
     * @param method 代理方法
     * @param jobName Job名称
     * @param jobGroup Job分组
     * @param arguments 代理方法参数
     * @return JobDetail
     * @author WangPanYong
     * @since 2021/04/13
     */
    private JobDetail buildJobDetail(Object object, String method, String jobName, String jobGroup
        , Object[] arguments) throws NoSuchMethodException, ClassNotFoundException {
        MethodInvokingJobDetailFactoryBean factoryBean = new MethodInvokingJobDetailFactoryBean();
        factoryBean.setTargetObject(object);
        factoryBean.setTargetMethod(method);
        factoryBean.setName(jobName);
        factoryBean.setGroup(jobGroup);
        if (arguments != null) {
            factoryBean.setArguments(arguments);
        }
        factoryBean.afterPropertiesSet();
        return factoryBean.getObject();
    }

    /**
     * @param jobDetail job
     * @param cronExpression cron表达式
     * @param triggerName 触发器名称
     * @param triggerGroup 触发器分组
     * @return Trigger
     * @author WangPanYong
     * @since 2021/04/13
     */
    private Trigger buildCronTrigger(JobDetail jobDetail, String cronExpression, String triggerName, String triggerGroup) {
        return TriggerBuilder.newTrigger()
                             .forJob(jobDetail)
                             .withIdentity(triggerName, triggerGroup)
                             .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                             .build();
    }


}
